/*
 * Copyright (c) 2018-2999 九五云信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.api.controller;


import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import com.yami.shop.bean.app.param.CheckRegisterSmsParam;
import com.yami.shop.bean.app.param.SendEmailParam;
import com.yami.shop.bean.app.param.SendSmsParam;
import com.yami.shop.bean.app.param.UserRegisterParam;
import com.yami.shop.bean.enums.SendType;
import com.yami.shop.bean.model.User;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.IPHelper;
import com.yami.shop.common.util.PrincipalUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.config.WxConfig;
import com.yami.shop.security.api.model.YamiUser;
import com.yami.shop.security.api.service.YamiUserDetailsService;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.security.comment.enums.App;
import com.yami.shop.security.comment.handler.LoginAuthSuccessHandler;
import com.yami.shop.security.comment.model.AppConnect;
import com.yami.shop.security.comment.service.AppConnectService;
import com.yami.shop.security.comment.token.AuthenticationToken;
import com.yami.shop.service.SmsLogService;
import com.yami.shop.service.UserService;
import com.yami.shop.service.impl.VerificationCodeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Date;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 用户信息
 * @author LGH
 */
@RestController
@RequestMapping("/user")
@Api(tags="用户注册相关接口")
@AllArgsConstructor
public class UserRegisterController {

	private final VerificationCodeService verificationCodeService;

	private final UserService userService;

	private final SmsLogService smsLogService;

	private final AppConnectService appConnectService;

	private final LoginAuthSuccessHandler loginAuthSuccessHandler;

	private final WxConfig wxConfig;

	private final YamiUserDetailsService yamiUserDetailsService;

	private final PasswordEncoder passwordEncoder;


	public static final String CHECK_REGISTER_SMS_FLAG = "checkRegisterSmsFlag";

	public static final String CHECK_UPDATE_PWD_SMS_FLAG = "updatePwdSmsFlag";

	@PutMapping("/sendRegisterSms")
	@ApiOperation(value="发送注册验证码", notes="发送注册验证码")
	public ResponseEntity<Void> register(@Valid @RequestBody SendSmsParam sendSmsParam) {
		if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, sendSmsParam.getMobile())) > 0) {
			// 该手机号已注册，无法重新注册
			throw new YamiShopBindException("yami.user.phone.exist");
		}
		// 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
		smsLogService.sendSms(SendType.REGISTER, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
		return ResponseEntity.ok().build();
	}

	/**
	 * 发送验证码到 QQ 邮箱
	 */
	@PostMapping  ("/sendEmailCode")
	@ApiOperation(value="发送邮箱注册验证码", notes="发送邮箱注册验证码")
	public ResponseEntity<Void> sendVerificationCode(@RequestBody SendEmailParam email) {
		verificationCodeService.sendVerificationCode(email.getEmail());
		return ResponseEntity.ok().build();
	}
	/**
	 * 验证用户输入的验证码
	 */
	@PostMapping("/verifyCode")
	public ResponseEntity<String> verifyCode(@RequestParam String email, @RequestParam String code) {
		boolean isValid = verificationCodeService.verifyCode(email, code);
		if (isValid) {
			return ResponseEntity.ok().build();
		} else {
			throw new YamiShopBindException("yami.user.code.error");
		}
	}


	@PutMapping("/checkRegisterSms")
	@ApiOperation(value="校验验证码", notes="校验验证码返回校验成功的标识")
	public ResponseEntity<String> register(@Valid @RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
		// 每个ip每分钟只能发十个注册的验证码，免得接口被利用
		if (!smsLogService.checkValidCode(checkRegisterSmsParam.getMobile(), checkRegisterSmsParam.getValidCode(), SendType.REGISTER)){
			// 验证码有误或已过期
			throw new YamiShopBindException("yami.user.code.error");
		}
		String checkRegisterSmsFlag = IdUtil.simpleUUID();
		RedisUtil.set(CHECK_REGISTER_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
		return ResponseEntity.ok(checkRegisterSmsFlag);
	}

	@PutMapping("/sendBindSms")
	@ApiOperation(value="发送绑定验证码", notes="发送绑定验证码")
	public ResponseEntity<Void> bindSms(@Valid @RequestBody SendSmsParam sendSmsParam) {
		// 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
		smsLogService.sendSms(SendType.VALID, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
		return ResponseEntity.ok().build();
	}

	@PutMapping("/registerOrBindUser")
	@ApiOperation(value="注册或绑定手机号", notes="用户注册或绑定手机号接口")
	public ResponseEntity<Void> register(HttpServletRequest request, HttpServletResponse response, @Valid @RequestBody UserRegisterParam userRegisterParam) {

		String mobile = userRegisterParam.getMobile();
		AppConnect appConnect = null;
		User user = null;
		String bizUserId = null;
		boolean isWxAppId = Objects.equals(userRegisterParam.getAppType(), App.MINI.value()) || Objects.equals(userRegisterParam.getAppType(), App.MP.value());
		if(isWxAppId) {
			bizUserId = SecurityUtils.getUser().getBizUserId();
		}

		// 正在进行注册，通过验证码校验
		if (Objects.equals(userRegisterParam.getRegisterOrBind(), 1)) {

			// 看看有没有校验验证码成功的标识
			userService.validate(userRegisterParam, CHECK_REGISTER_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
			// 正在进行申请注册
			if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile,userRegisterParam.getMobile())) > 0) {
				// 该手机号已注册，无法重新注册
				throw new YamiShopBindException("yami.user.phone.exist");
			}
		}
		// 小程序注册/绑定手机号
		else {
			YamiUser yamiUser = SecurityUtils.getUser();
			appConnect = appConnectService.getByBizUserId(yamiUser.getBizUserId(), yamiUser.getAppType());

			// 通过微信手机号校验
			if (Objects.equals(2, userRegisterParam.getValidateType())) {
				try {
					WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxConfig.getWxMaService().getUserService().getPhoneNoInfo(yamiUser.getSessionKey(), userRegisterParam.getEncryptedData(), userRegisterParam.getIvStr());
					mobile = wxMaPhoneNumberInfo.getPhoneNumber();

				} catch (Exception e) {
					// 授权失败，请重新授权
					throw new YamiShopBindException("yami.auth.fail");
				}
				if (StrUtil.isBlank(mobile)) {
					// 无法获取用户手机号信息
					throw new YamiShopBindException("yami.user.no.get.phone");
				}
				user = yamiUserDetailsService.loadUserByMobileOrUserName(mobile, 0);
			}
			// 通过账号密码校验
			else if (Objects.equals(3, userRegisterParam.getValidateType())) {
				user = yamiUserDetailsService.loadUserByMobileOrUserName(mobile, 0);
				if (user == null) {
					// 账号或密码不正确
					throw new YamiShopBindException("yami.user.account.error");
				}
				String encodedPassword = user.getLoginPassword();
				String rawPassword = userRegisterParam.getPassword();
				// 密码不正确
				if (StrUtil.isBlank(encodedPassword) || !passwordEncoder.matches(rawPassword,encodedPassword)){
					// 账号或密码不正确
					throw new YamiShopBindException("yami.user.account.error");
				}
			}
			// 通过验证码校验
			else {
				if (!smsLogService.checkValidCode(userRegisterParam.getMobile(), userRegisterParam.getValidCode(), SendType.VALID)){
					// 验证码有误或已过期
					throw new YamiShopBindException("yami.user.code.error");
				}
			}
		}

		Date now = new Date();

		// 尝试用手机号获取用户信息
		if (user == null && StrUtil.isNotBlank(mobile)) {
			user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile,mobile));
		}

		// 新建用户
		if (user == null) {
			user = new User();
			if (StrUtil.isBlank(userRegisterParam.getUserName())) {
				userRegisterParam.setUserName(mobile);
			}

			// 如果有用户名,就判断用户名格式是否正确
			if (!PrincipalUtil.isUserName(userRegisterParam.getUserName())) {
				// 用户名应由4-16位数字字母下划线组成
				throw new YamiShopBindException("yami.user.name.check");
			}

			user.setModifyTime(now);
			user.setUserRegtime(now);
			user.setUserRegip(IPHelper.getIpAddr());
			user.setStatus(1);

			user.setPic(userRegisterParam.getImg());
			user.setUserMobile(mobile);
			user.setUserName(userRegisterParam.getUserName());
			if (StrUtil.isNotBlank(userRegisterParam.getPassword())) {
				user.setLoginPassword(passwordEncoder.encode(userRegisterParam.getPassword()));
			}
			// 用户名就是默认的昵称
			user.setNickName(StrUtil.isBlank(userRegisterParam.getNickName())? userRegisterParam.getUserName(): userRegisterParam.getNickName());
		}
		if(Objects.nonNull(bizUserId) && isWxAppId){
			appConnect = new AppConnect();
			appConnect.setBizUserId(bizUserId);
		}
		appConnectService.registerOrBindUser(user, appConnect, userRegisterParam.getAppType());


		//进行授权登录
		UserDetails userDetails = yamiUserDetailsService.getYamiUser(userRegisterParam.getAppType(),user, bizUserId);
		AuthenticationToken authenticationToken = new AuthenticationToken();
		authenticationToken.setPrincipal(user.getUserMobile());
		authenticationToken.setCredentials(user.getLoginPassword());
		authenticationToken.setPrincipal(userDetails.getUsername());
		authenticationToken.setDetails(userDetails);
		authenticationToken.setAuthenticated(true);
		loginAuthSuccessHandler.onAuthenticationSuccess(request,response,authenticationToken);

		return ResponseEntity.ok().build();
	}


	@PutMapping("/checkUpdatePwdSms")
	@ApiOperation(value="修改密码校验验证码", notes="校验验证码返回校验成功的标识")
	public ResponseEntity<String> checkUpdatePwdSms(@RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {

		boolean isCheckPass = false;
		if (Objects.nonNull(checkRegisterSmsParam) && Objects.nonNull(checkRegisterSmsParam.getMobile())){
			Matcher m = Pattern.compile(PrincipalUtil.MOBILE_REGEXP).matcher(checkRegisterSmsParam.getMobile());
			isCheckPass = m.matches();

		}
		if (!isCheckPass){
			throw new YamiShopBindException("yami.user.err.phone");
		}

		User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, checkRegisterSmsParam.getMobile()));
		if (user == null) {
			// 此用户不存在，请先注册
			throw new YamiShopBindException("yami.user.account.no.exist");
		}
		if (!smsLogService.checkValidCode(user.getUserMobile(), checkRegisterSmsParam.getValidCode(), SendType.UPDATE_PASSWORD)){
			// 验证码有误或已过期
			throw new YamiShopBindException("yami.user.code.error");
		}
		String checkRegisterSmsFlag = IdUtil.simpleUUID();
		RedisUtil.set(CHECK_UPDATE_PWD_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
		return ResponseEntity.ok(checkRegisterSmsFlag);
	}

	@PutMapping("/updatePwd")
	@ApiOperation(value="修改密码", notes="修改密码")
	public ResponseEntity<Void> updatePwd(@Valid @RequestBody UserRegisterParam userRegisterParam) {
		User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userRegisterParam.getMobile()));
		if (user == null) {
			// 无法获取用户信息
			throw new YamiShopBindException("yami.user.no.exist");
		}
		// 看看有没有校验验证码成功的标识
		userService.validate(userRegisterParam, CHECK_UPDATE_PWD_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
		if (StrUtil.isBlank(userRegisterParam.getPassword())) {
			// 新密码不能为空
			throw new YamiShopBindException("yami.user.password.no.exist");
		}
		if (StrUtil.equals(passwordEncoder.encode(userRegisterParam.getPassword()),user.getLoginPassword())) {
			// 新密码不能与原密码相同!
			throw new YamiShopBindException("yami.user.password.check");
		}
		user.setModifyTime(new Date());
		user.setLoginPassword(passwordEncoder.encode(userRegisterParam.getPassword()));
		userService.updateById(user);
		return ResponseEntity.ok().build();
	}
}
